#include <iostream>
#include <ctime>
#include <unistd.h>
#include <cstdlib>
#include "RingQueue.hpp"
using namespace std;

#define PTHREADNUM 2
#define CTHREADNUM 4

pthread_mutex_t stdoutMutex = PTHREAD_MUTEX_INITIALIZER;

class ThreadData
{
public:
    string name_;
    RingQueue<int> *rq_;
};

void *producer(void *argv)
{
    while (true)
    {
        sleep(1);
        int data = rand() % 100;
        ThreadData *td = (ThreadData *)argv;
        td->rq_->push(data);
        pthread_mutex_lock(&stdoutMutex);
        cout << td->name_ << " produce a data:" << data << endl;
        pthread_mutex_unlock(&stdoutMutex);
    }
    return nullptr;
}

void *consumer(void *argv)
{
    while (true)
    {
        ThreadData *td = (ThreadData *)argv;
        int data = td->rq_->pop();
        pthread_mutex_lock(&stdoutMutex);
        cout << td->name_ << " consume a data:" << data << endl;
        pthread_mutex_unlock(&stdoutMutex);
    }
    return nullptr;
}

int main()
{
    srand(time(nullptr) ^ getpid());
    pthread_t p[PTHREADNUM], c[CTHREADNUM];
    RingQueue<int> *rq = new RingQueue<int>();

    for (int i = 0; i < PTHREADNUM; i++)
    {
        ThreadData *td = new ThreadData();
        td->rq_ = rq;
        td->name_ = "PThread" + to_string(i);
        pthread_create(&p[i], nullptr, producer, (void *)td);
    }

    for (int i = 0; i < CTHREADNUM; i++)
    {
        ThreadData *td = new ThreadData();
        td->rq_ = rq;
        td->name_ = "CThread" + to_string(i);
        pthread_create(&c[i], nullptr, consumer, (void *)td);
    }

    for (int i = 0; i < PTHREADNUM; i++)
        pthread_join(p[i], nullptr);
    for (int i = 0; i < CTHREADNUM; i++)
        pthread_join(c[i], nullptr);

    delete rq;
    rq = nullptr;
    return 0;
}